import axios, { AxiosInstance } from 'axios';
import {
  DataSourceAdapter,
  DataSourceConfig,
  StandardAlert,
  DataSourceType,
} from '@/types/datasource.types';
import logger from '@utils/logger';

/**
 * Prometheus/Alertmanager 数据源适配器
 */
export class PrometheusAdapter implements DataSourceAdapter {
  public readonly type = DataSourceType.PROMETHEUS;
  private client: AxiosInstance;

  constructor() {
    this.client = axios.create();
  }

  /**
   * 测试连接
   */
  async testConnection(config: DataSourceConfig): Promise<{
    success: boolean;
    message: string;
    latency?: number;
  }> {
    const startTime = Date.now();

    try {
      // 测试 Prometheus
      const prometheusUrl = config.connection.url;
      const prometheusResponse = await axios.get(`${prometheusUrl}/-/healthy`, {
        timeout: config.connection.timeout || 5000,
        headers: config.connection.headers,
      });

      // 测试 Alertmanager (如果配置了)
      const alertmanagerUrl = config.connection.url.replace(':9090', ':9093');
      let alertmanagerHealthy = false;

      try {
        const alertmanagerResponse = await axios.get(`${alertmanagerUrl}/-/healthy`, {
          timeout: config.connection.timeout || 5000,
        });
        alertmanagerHealthy = alertmanagerResponse.status === 200;
      } catch (error) {
        logger.warn('Alertmanager health check failed, but Prometheus is healthy');
      }

      const latency = Date.now() - startTime;

      return {
        success: prometheusResponse.status === 200,
        message: alertmanagerHealthy
          ? 'Prometheus and Alertmanager connection successful'
          : 'Prometheus connection successful (Alertmanager not available)',
        latency,
      };
    } catch (error: any) {
      return {
        success: false,
        message: `Connection failed: ${error.message}`,
        latency: Date.now() - startTime,
      };
    }
  }

  /**
   * 获取告警列表
   */
  async fetchAlerts(
    config: DataSourceConfig,
    options?: {
      startTime?: Date;
      endTime?: Date;
      filters?: Record<string, any>;
    }
  ): Promise<StandardAlert[]> {
    try {
      const alertmanagerUrl = config.connection.url.replace(':9090', ':9093');
      const response = await axios.get(`${alertmanagerUrl}/api/v1/alerts`, {
        timeout: config.connection.timeout || 30000,
        headers: config.connection.headers,
      });

      if (response.data.status !== 'success') {
        throw new Error('Failed to fetch alerts from Alertmanager');
      }

      const rawAlerts = response.data.data || [];

      // 转换为标准格式
      let alerts = rawAlerts.map((alert: any) => this.transformAlert(alert, config));

      // 应用过滤规则
      alerts = this.applyFilters(alerts, config);

      // 应用时间范围过滤
      if (options?.startTime || options?.endTime) {
        alerts = alerts.filter((alert: any) => {
          const alertTime = alert.startsAt;
          if (options.startTime && alertTime < options.startTime) return false;
          if (options.endTime && alertTime > options.endTime) return false;
          return true;
        });
      }

      return alerts;
    } catch (error: any) {
      logger.error(`Failed to fetch alerts from Prometheus: ${error.message}`);
      throw error;
    }
  }

  /**
   * 转换告警为标准格式
   */
  transformAlert(rawData: any, config: DataSourceConfig): StandardAlert {
    const mapping = config.mapping;

    // 映射严重级别
    const rawSeverity = rawData.labels?.severity || 'unknown';
    const severity = this.mapSeverity(rawSeverity, config.valueMapping?.severity);

    // 映射状态
    const rawStatus = rawData.status?.state || 'active';
    const status = this.mapStatus(rawStatus, config.valueMapping?.status);

    return {
      id: rawData.fingerprint || this.generateId(rawData),
      sourceId: config.id,
      sourceType: DataSourceType.PROMETHEUS,
      alertname: rawData.labels?.alertname || 'Unknown Alert',
      severity,
      status,
      instance: rawData.labels?.instance || 'unknown',
      startsAt: new Date(rawData.startsAt),
      endsAt: rawData.endsAt ? new Date(rawData.endsAt) : undefined,
      description: rawData.annotations?.description || rawData.annotations?.summary || '',
      labels: rawData.labels || {},
      annotations: rawData.annotations || {},
      fingerprint: rawData.fingerprint || this.generateId(rawData),
      rawData,
    };
  }

  /**
   * 健康检查
   */
  async healthCheck(config: DataSourceConfig): Promise<boolean> {
    try {
      const result = await this.testConnection(config);
      return result.success;
    } catch (error) {
      return false;
    }
  }

  /**
   * 映射严重级别
   */
  private mapSeverity(
    rawSeverity: string,
    mapping?: Record<string, 'critical' | 'high' | 'medium' | 'low'>
  ): 'critical' | 'high' | 'medium' | 'low' {
    if (mapping && mapping[rawSeverity]) {
      return mapping[rawSeverity];
    }

    // 默认映射
    const normalizedSeverity = rawSeverity.toLowerCase();
    if (['critical', 'p1', 'sev1'].includes(normalizedSeverity)) return 'critical';
    if (['high', 'warning', 'p2', 'sev2'].includes(normalizedSeverity)) return 'high';
    if (['medium', 'p3', 'sev3'].includes(normalizedSeverity)) return 'medium';
    if (['low', 'info', 'p4', 'sev4'].includes(normalizedSeverity)) return 'low';

    return 'medium'; // 默认值
  }

  /**
   * 映射状态
   */
  private mapStatus(
    rawStatus: string,
    mapping?: Record<string, 'firing' | 'resolved' | 'acknowledged'>
  ): 'firing' | 'resolved' | 'acknowledged' {
    if (mapping && mapping[rawStatus]) {
      return mapping[rawStatus];
    }

    // 默认映射
    const normalizedStatus = rawStatus.toLowerCase();
    if (['active', 'firing', 'open'].includes(normalizedStatus)) return 'firing';
    if (['resolved', 'closed', 'ok'].includes(normalizedStatus)) return 'resolved';
    if (['acknowledged', 'acked', 'silenced'].includes(normalizedStatus)) return 'acknowledged';

    return 'firing'; // 默认值
  }

  /**
   * 应用过滤规则
   */
  private applyFilters(alerts: StandardAlert[], config: DataSourceConfig): StandardAlert[] {
    if (!config.filters) return alerts;

    let filtered = alerts;

    // 应用包含规则
    if (config.filters.includeRules && config.filters.includeRules.length > 0) {
      filtered = filtered.filter((alert) =>
        config.filters!.includeRules!.some((rule) => this.matchRule(alert, rule))
      );
    }

    // 应用排除规则
    if (config.filters.excludeRules && config.filters.excludeRules.length > 0) {
      filtered = filtered.filter((alert) =>
        !config.filters!.excludeRules!.some((rule) => this.matchRule(alert, rule))
      );
    }

    return filtered;
  }

  /**
   * 检查告警是否匹配规则
   */
  private matchRule(alert: StandardAlert, rule: any): boolean {
    const fieldValue = this.getFieldValue(alert, rule.field);

    if (fieldValue === undefined) return false;

    switch (rule.operator) {
      case 'equals':
        return fieldValue === rule.value;
      case 'contains':
        return String(fieldValue).includes(String(rule.value));
      case 'startsWith':
        return String(fieldValue).startsWith(String(rule.value));
      case 'endsWith':
        return String(fieldValue).endsWith(String(rule.value));
      case 'regex':
        return new RegExp(String(rule.value)).test(String(fieldValue));
      case 'gt':
        return Number(fieldValue) > Number(rule.value);
      case 'lt':
        return Number(fieldValue) < Number(rule.value);
      case 'gte':
        return Number(fieldValue) >= Number(rule.value);
      case 'lte':
        return Number(fieldValue) <= Number(rule.value);
      default:
        return false;
    }
  }

  /**
   * 获取字段值
   */
  private getFieldValue(alert: StandardAlert, field: string): any {
    // 支持嵌套字段访问，如 "labels.severity"
    const parts = field.split('.');
    let value: any = alert;

    for (const part of parts) {
      if (value && typeof value === 'object') {
        value = value[part];
      } else {
        return undefined;
      }
    }

    return value;
  }

  /**
   * 生成唯一 ID
   */
  private generateId(rawData: any): string {
    const str = JSON.stringify(rawData);
    let hash = 0;
    for (let i = 0; i < str.length; i++) {
      const char = str.charCodeAt(i);
      hash = (hash << 5) - hash + char;
      hash = hash & hash; // Convert to 32bit integer
    }
    return Math.abs(hash).toString(16);
  }
}
